package com.sxx.mall.order.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxx.commons.constant.OrderConstant;
import com.sxx.commons.exception.NoStockException;
import com.sxx.commons.utils.PageUtils;
import com.sxx.commons.utils.Query;
import com.sxx.commons.utils.R;
import com.sxx.commons.vo.MemberVO;
import com.sxx.mall.order.dao.OrderDao;
import com.sxx.mall.order.dto.OrderCreateDTO;
import com.sxx.mall.order.entity.OrderEntity;
import com.sxx.mall.order.entity.OrderItemEntity;
import com.sxx.mall.order.feign.CartFeignService;
import com.sxx.mall.order.feign.MemberFeignService;
import com.sxx.mall.order.feign.ProductService;
import com.sxx.mall.order.feign.WareFeignService;
import com.sxx.mall.order.interceptor.AuthIntercepter;
import com.sxx.mall.order.service.OrderItemService;
import com.sxx.mall.order.service.OrderService;
import com.sxx.mall.order.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    CartFeignService cartFeignService;

    @Autowired
    ThreadPoolExecutor executor;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    ProductService productService;

    @Autowired
    OrderService orderService;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    WareFeignService wareFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVO confirmOrder() {
        OrderConfirmVO confirmVO = new OrderConfirmVO();
        MemberVO memberVO = AuthIntercepter.threadLocal.get();
        //获取到requestContextHolder的相关信息
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            Long id = memberVO.getId();
            // 1.查询当前登录用户对应的会员的地址信息
            List<MemberAddressVO> address = memberFeignService.getAddress(id);
            confirmVO.setAddress(address);
        }, executor);
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            // 2.查询购物车中选中的商品信息
            List<OrderItemVO> orderItems = cartFeignService.getCartToConfirm();
            confirmVO.setItems(orderItems);
            // 3.计算订单的总金额和需要支付的总金额 VO自动计算
        }, executor);
        try {
            CompletableFuture.allOf(future1,future2).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //4.生成防重的token
        String token = UUID.randomUUID().toString().replace("-", "");
        //token存储到redis
        redisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PERFIX+":"+memberVO.getId(),token);
        confirmVO.setOrderToken(token);
        return confirmVO;
    }
    private Lock lock = new ReentrantLock();

    @Transactional
    @Override
    public OrderResponseVO submitOrder(OrderSubmitVO vo) throws NoStockException{
        //响应对象
        OrderResponseVO responseVO = new OrderResponseVO();
        //获取当前登录对象
        MemberVO memberVO = AuthIntercepter.threadLocal.get();
        //1.验证是否重复提交
        String key = OrderConstant.ORDER_TOKEN_PERFIX + ":" + memberVO.getId();
        //lua脚本保证原子性
        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long result = (Long) redisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class),
                Arrays.asList(key),
                vo.getOrderToken());
        if (result == 0){
            //表示验证失败，说明是重复提交
            responseVO.setCode(1);
            return responseVO;
        }
        /*        try {
            lock.lock();//加锁
            String redisToken = (String) redisTemplate.opsForValue().get(key);
            if (redisToken != null && redisToken.equals(vo.getOrderToken())){
                //表示第一次提交

                //需要删除token
                redisTemplate.delete(key);

            }else {
                return responseVO;
            }
        }finally {
            lock.unlock();//释放锁
        }*/
        //表示第一次提交
        //2创建订单
        OrderCreateDTO orderCreateDTO = createOrder(vo);
        responseVO.setOrderEntity(orderCreateDTO.getOrderEntity());
        //3.保存订单信息
        savaOrder(orderCreateDTO);
        //4.锁定库存
        WareSkuLockVO wareSkuLockVO = new WareSkuLockVO();
        wareSkuLockVO.setOrderSN(orderCreateDTO.getOrderEntity().getOrderSn());
        List<OrderItemVO> orderItemVOS = orderCreateDTO.getOrderItemEntitys().stream().map(item -> {
            OrderItemVO orderItemVO = new OrderItemVO();
            orderItemVO.setSkuId(item.getSkuId());
            orderItemVO.setTitle(item.getSkuName());
            orderItemVO.setCount(item.getSkuQuantity());
            return orderItemVO;
        }).collect(Collectors.toList());
        wareSkuLockVO.setItems(orderItemVOS);
        R r = wareFeignService.orderLockStock(wareSkuLockVO);
        if (r.getCode() == 0){
            //表示锁定库存成功
            responseVO.setCode(0);//订单创建成功
        }else {
            //锁定库存失败
            responseVO.setCode(2);//库存不足
            throw new NoStockException(12000l);
        }

        return responseVO;
    }

    /*
    * 保存订单数据
    * */
    private void savaOrder(OrderCreateDTO orderCreateDTO) {

        //1.订单项数据
        List<OrderItemEntity> orderItemEntitys = orderCreateDTO.getOrderItemEntitys();
        orderItemService.saveBatch(orderItemEntitys);
        //2.订单数据
        //根据dto拿到部分数据
        OrderEntity orderEntity = orderCreateDTO.getOrderEntity();
        //根据订单项收集订单数据
        BigDecimal totalAmout = new BigDecimal(0);
        Integer integration = 0;
        Integer growth = 0;

        for (OrderItemEntity orderItemEntity : orderItemEntitys) {
            BigDecimal itemPrice = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));
            totalAmout = totalAmout.add(itemPrice);
            integration = integration + orderItemEntity.getGiftIntegration();
            growth = growth + orderItemEntity.getGiftGrowth();
        }
        orderEntity.setTotalAmount(totalAmout);
        orderEntity.setPayAmount(totalAmout);
        orderEntity.setStatus(0);
        orderEntity.setAutoConfirmDay(7);
        orderEntity.setIntegration(integration);
        orderEntity.setGrowth(growth);
        //保存订单
        orderService.save(orderEntity);

    }

    /**
     * 创建订单的方法
     * @param vo
     * @return
     */
    private OrderCreateDTO createOrder(OrderSubmitVO vo) {
        OrderCreateDTO orderCreateDTO = new OrderCreateDTO();
        //创建OrderEntity
        OrderEntity orderEntity = buildOrder(vo);
        orderCreateDTO.setOrderEntity(orderEntity);
        //创建OrderItemEntity
        List<OrderItemEntity> orderItemEntities = buildOrderItems(orderEntity.getOrderSn());
        orderCreateDTO.setOrderItemEntitys(orderItemEntities);
        return orderCreateDTO;
    }

    /**
     * 通过购物车选中的商品来创建对应的购物车项信息
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String orderSN) {
        ArrayList<OrderItemEntity> orderItemEntities = new ArrayList<>();
        //获取商品信息
        List<OrderItemVO> cartToConfirms = cartFeignService.getCartToConfirm();
        if (cartToConfirms !=null && cartToConfirms.size()>0){
            //统一根据skuId查询出对应的spu的信息
            List<Long> spuIds = new ArrayList<>();
            for (OrderItemVO orderItemVO : cartToConfirms) {
                if (!spuIds.contains(orderItemVO.getSpuId())){
                    spuIds.add(orderItemVO.getSpuId());
                }
            }
            Long[] spuIdsArray = new Long[spuIds.size()];
            //远程调用商品服务获取到对应的spu信息
            List<OrderItemSpuInfoVO> spuInfos = productService.getOrderItemSpuInfoBySpuId(spuIds.toArray(spuIdsArray));
            Map<Long, OrderItemSpuInfoVO> map = spuInfos.stream().collect(Collectors.toMap(OrderItemSpuInfoVO::getId, item -> item));
            for (OrderItemVO item : cartToConfirms) {
                OrderItemSpuInfoVO spuInfo = map.get(item.getSpuId());
                OrderItemEntity orderItemEntity = buildOrderItems(item,spuInfo);
                //绑定对应订单编号
                orderItemEntity.setOrderSn(orderSN);
                orderItemEntities.add(orderItemEntity);
            }
        }


        return orderItemEntities;
    }

    /**
     * 根据一个购物车中的商品 创建对应的订单项
     * @param item
     */
    private OrderItemEntity buildOrderItems(OrderItemVO item,OrderItemSpuInfoVO spuInfo) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        //sku信息
        orderItemEntity.setSkuId(item.getSkuId());
        orderItemEntity.setSkuName(item.getTitle());
        orderItemEntity.setSkuPrice(item.getPrice());
        orderItemEntity.setSkuPic(item.getImage());
        orderItemEntity.setSkuQuantity(item.getCount());
        String attrString = StringUtils.collectionToDelimitedString(item.getSkuAttr(), ";");
        orderItemEntity.setSkuAttrsVals(attrString);
        //spu信息
        orderItemEntity.setSpuId(spuInfo.getId());
        orderItemEntity.setSpuBrand(spuInfo.getBrandName());
        orderItemEntity.setSpuName(spuInfo.getSpuName());
        orderItemEntity.setSpuPic(spuInfo.getImg());
        orderItemEntity.setCategoryId(spuInfo.getCatalogId());
        //优惠信息 忽略
        //积分信息
        orderItemEntity.setGiftGrowth(item.getPrice().intValue());
        orderItemEntity.setGiftIntegration(item.getPrice().intValue());
        return orderItemEntity;
    }

    private OrderEntity buildOrder(OrderSubmitVO vo) {
        //创建OrderEntity
        OrderEntity orderEntity = new OrderEntity();
        //创建订单编号
        String orderSn = IdWorker.getTimeId();
        orderEntity.setOrderSn(orderSn);
        MemberVO memberVO = AuthIntercepter.threadLocal.get();
        //设置会员相关信息
        orderEntity.setMemberId(memberVO.getId());
        orderEntity.setMemberUsername(memberVO.getUsername());
        //根据收货地址id获取地址信息
        MemberAddressVO memberAddressVO = memberFeignService.getAddressById(vo.getAddrId());
        orderEntity.setReceiverCity(memberAddressVO.getCity());
        orderEntity.setReceiverName(memberAddressVO.getName());
        orderEntity.setReceiverPhone(memberAddressVO.getPhone());
        orderEntity.setReceiverProvince(memberAddressVO.getProvince());
        orderEntity.setReceiverDetailAddress(memberAddressVO.getDetailAddress());
        orderEntity.setReceiverPostCode(memberAddressVO.getPostCode());
        orderEntity.setReceiverRegion(memberAddressVO.getRegion());
        orderEntity.setStatus(OrderConstant.OrderStatusEnum.FOR_THE_PAYMENT.getCode());
        return orderEntity;
    }

}